Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3301 +/- ##
=======================================
Coverage 99.95% 99.95%
=======================================
Files 380 381 +1
Lines 53949 54020 +71
=======================================
+ Hits 53927 53998 +71
Misses 22 22 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@sergisiso @arporter This is ready for a first review. The implementation is currently pretty small and neat - if you want more functionality testing let me know and I can add more. |
arporter
left a comment
There was a problem hiding this comment.
Thanks very much Aidan - as you say it's pleasingly simple. Also as you say, it could do with some more checks and associated tests :-)
On the naming front, I worry that the use of Extract will be confused with the existing ExtractTrans which is obviously quite different. IAAI (two of them) and it seems that IntroduceLocal/TemporaryTrans is a good alternative that doesn't involve "Extract".
Finally, (once everything else is done) I think it would be exciting (and possibly educational) to try this for real. I'm thinking we'd alter nemo/scripts/utils.py::normalise_loops so that it e.g. looks for any Calls which have array expressions as arguments.
| """Applies the DataNodeExtractTransApplies to the input arguments. | ||
|
|
||
| :param node: The datanode to extract. | ||
| :param storage_name: The name of the temporary variable to store |
There was a problem hiding this comment.
Perhaps "The (base) name of the..." to indicate that it won't necessarily be exactly that name that is used. Also, please could you de-dent the following lines to just use four spaces so we don't need as many lines.
There was a problem hiding this comment.
I guess we need to decide if this should be a base name of if the storage_name argument is provided the name must be exact? Happy to go either way - if the name must be exact I should probably add it to validate.
There was a problem hiding this comment.
I can't imagine anyone ever caring that it was exact so I vote for it just being a suggestion (i.e. base_name).
There was a problem hiding this comment.
Changed this behaviour now.
…e into 1646_datanode_extract_trans
|
@arporter I think I fixed all the issues I found from the last review, ready for another look. |
arporter
left a comment
There was a problem hiding this comment.
Looking good @LonelyCat124 - I like your solution for the imported symbols.
I think it would be worth doing the renaming of the transformation now. Please could you also add it to the User Guide.
I've addded a real-life NEMO example to #1958 - please could you use that as the basis for an additional test?
| scoped_name_sym = scope_symbols.get(sym.name, None) | ||
| if scoped_name_sym and sym is not scoped_name_sym: | ||
| raise TransformationError( | ||
| f"Input node contains an imported symbol whose " |
There was a problem hiding this comment.
It took me a while to work out what this check was for. Could you extend the text to say that the "The type of the node supplied to {self.name} depends upon an imported symbol ('{sym.name}') which has a name clash with a symbol in the current scope."
| f"DataNodeExtractTrans cannot be applied. " | ||
| f"Clashing symbol name is '{sym.name}'." | ||
| ) | ||
| # If its an imported symbol we need to check if its |
There was a problem hiding this comment.
I think we want this check as part of the previous one as we may have the same symbol imported from the same location but represented by different Symbol instances. i.e. sym is not scoped_name_sym but, if they are both imported from the same module, they must be representing the same variable.
There was a problem hiding this comment.
@arporter I did wonder about this initially, but couldn't find a way to create a test where it happened, so abandoned it, but I'll have another go since you also think it should be possible.
There was a problem hiding this comment.
Yeah I found a way to test this now when looking at another comment.
There was a problem hiding this comment.
Done I think - at least for validate, need to think about apply.
There was a problem hiding this comment.
Actually apply should be ok, but i'm a bit confused, i make symbol copies and put them in the symbol table and then just don't reference them anywhere (including not reforming the shape appropriately) so I'm a little confused.
There was a problem hiding this comment.
I'm so confused by symbols every time i try to work with them, I think I need to pause and double check all the symbols being created are used where i expect afterwards and are in the symbol table.
There was a problem hiding this comment.
Fixed now I think.
| f"so the DataNodeExtractTrans cannot be applied. " | ||
| f"Input node was '{node.debug_string().strip()}'." | ||
| ) | ||
| # Otherwise we have an ArrayBounds |
There was a problem hiding this comment.
I need a bit more help following this code. Perhaps, "...ArrayBounds - check to see which Symbols are referenced in those bounds."
| symbols.update(element.lower.get_all_accessed_symbols()) | ||
| if isinstance(element.upper, DataNode): | ||
| symbols.update(element.upper.get_all_accessed_symbols()) | ||
| scope_symbols = node.scope.symbol_table.get_symbols() |
There was a problem hiding this comment.
"Compare these symbols with those already in scope at node"
| f"whose containing module collides with an " | ||
| f"existing symbol. Colliding name is " | ||
| f"'{sym.interface.container_symbol.name}'." | ||
| ) |
There was a problem hiding this comment.
Unfortunately we also have to allow for a situation when the type of the imported variable (a_var in this case) depends on private variables:
module some_other_mod
integer, parameter :: dim1 = 4, dim2 = 5
real(kind=wp), dimension(dim1, dim2) :: a_var
public :: a_var
private
end modulein which case we can't import the symbols that define the shape of the array. You'll need to check their visibility in the symbol_table associated with the Container pointed to by the import interface of a_var.
There was a problem hiding this comment.
@arporter I'm a bit confused when trying to do this test - when I examine the interface of dim1 and dim2 (as found in the size of the a_var.datatype)I don't get an ImportInterface but instead a StaticInterface. Is this expected behaviour? If so, how can I differentiate between two private static variables where one is in the current scope and one is from a "resolve imports" module?
There was a problem hiding this comment.
Yeah, I'm not sure how to tell the difference between the dim/dim2 symbols in your example, and x in this code:
implicit none
integer, parameter, private :: x = 1
private
contains
subroutine sub()
integer :: i
i = x
end subroutine sub
end module test
I could check that if its a static variable then it has to be in the scope? But why are those not ImportInterface symbols despite being static?
| code = """subroutine test() | ||
| use a_mod, only: some_var | ||
| use some_mod, only: j | ||
| j = some_var(1,3) |
There was a problem hiding this comment.
Picky but j is a parameter so can't be assigned to.
| assign = psyir.walk(Assignment)[0] | ||
| with pytest.raises(TransformationError) as err: | ||
| dtrans.validate(assign.rhs) | ||
| assert ("Input node contains an imported symbol whose containing module " |
There was a problem hiding this comment.
"...symbol ('sym.name') whose ..."
| psyir = fortran_reader.psyir_from_source(code) | ||
| assign = psyir.walk(Assignment)[0] | ||
| dtrans.apply(assign.rhs, storage_name="temporary") | ||
| out = fortran_writer(psyir) |
There was a problem hiding this comment.
Pls could you add checks that the code compiles. (assert Compile(tmpdir).string_compiles(out))
Also, following @hiker pointing out that tmp_path is the replacement for tmpdir, please could you switch to using that?
| assert """ tmp = 3 * b | ||
| a(:4) = tmp""" in out | ||
|
|
||
| # Test the imports are handled correctly. |
There was a problem hiding this comment.
I think the following could be a separate test.
| assign = psyir.walk(Assignment)[0] | ||
| dtrans.apply(assign.rhs) | ||
| out = fortran_writer(psyir) | ||
| assert """ integer, dimension(25,50) :: tmp |
There was a problem hiding this comment.
Compilation checks for these various checks please (if possible).
Initial implementation - transformation is quite straightforward so should be good for a review assuming CI is ok.